package com.zhuanzhuan.hero.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bj58.youpin.common.utils.json.JsonUtils;
import com.zhuanzhuan.hero.user.consts.Consts;
import com.zhuanzhuan.hero.user.consts.NumConsts;
import com.zhuanzhuan.hero.user.converter.LabelConverter;
import com.zhuanzhuan.hero.user.dto.label.QueryBrandModelLabelDTO;
import com.zhuanzhuan.hero.user.entity.HeroLabelInfo;
import com.zhuanzhuan.hero.user.enums.*;
import com.zhuanzhuan.hero.user.exception.BusinessException;
import com.zhuanzhuan.hero.user.mapper.HeroLabelInfoMapper;
import com.zhuanzhuan.hero.user.mq.dto.BackBusinessLabelUpdateMsg;
import com.zhuanzhuan.hero.user.mq.producer.HeroUserProducer;
import com.zhuanzhuan.hero.user.pojo.bo.*;
import com.zhuanzhuan.hero.user.pojo.po.LabelRelateNumPO;
import com.zhuanzhuan.hero.user.pojo.po.QueryBusinessLabelRelatePO;
import com.zhuanzhuan.hero.user.service.HeroLabelInfoService;
import com.zhuanzhuan.hero.user.service.HeroUserLabelRelationService;
import com.zhuanzhuan.hero.user.service.IApolloService;
import com.zhuanzhuan.hero.user.service.IPanGuService;
import com.zhuanzhuan.hero.user.util.Assert;
import com.zhuanzhuan.hero.user.vo.label.LevelLabelVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * dal Interface:HeroLabelInfo
 *
 * @author hanjunjun
 * @date 2024-6-21
 */
@Service
@Slf4j
public class HeroLabelInfoServiceImpl extends ServiceImpl<HeroLabelInfoMapper, HeroLabelInfo>
        implements HeroLabelInfoService {

    @Resource
    private IApolloService apolloService;

    @Resource
    private HeroUserLabelRelationService userLabelRelationService;

    @Resource
    private IPanGuService panGuService;

    @Resource
    private HeroUserProducer heroUserProducer;

    @Override
    public HeroLabelInfo queryById(Long id) {
        return this.getById(id);
    }

    @Override
    public List<HeroLabelInfo> listById(List<Long> ids) {
        LambdaQueryWrapper<HeroLabelInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(HeroLabelInfo::getId, ids)
                .eq(HeroLabelInfo::getState, StateEnum.EFFECTIVE.getCode());
        return this.list(queryWrapper);
    }

    @Override
    public List<HeroLabelInfo> listByParam(LabelInfoQueryBO query) {
        LambdaQueryWrapper<HeroLabelInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(CollectionUtils.isNotEmpty(query.getIds()), HeroLabelInfo::getId,
                        query.getIds())
                .eq(Objects.nonNull(query.getLabelType()), HeroLabelInfo::getLabelType,
                        query.getLabelType())
                .eq(Objects.nonNull(query.getLabelName()), HeroLabelInfo::getLabelName,
                        query.getLabelName())
                .eq(Objects.nonNull(query.getCreateUid()), HeroLabelInfo::getCreateBy,
                        query.getCreateUid())
                .eq(StringUtils.isNotBlank(query.getParentLabelCode()), HeroLabelInfo::getParentLabelCode,
                        query.getParentLabelCode())
                .eq(Objects.nonNull(query.getLabelLevel()), HeroLabelInfo::getLabelLevel,
                        query.getLabelLevel())
                .ge(Objects.nonNull(query.getMinLabelLevel()), HeroLabelInfo::getLabelLevel,
                        query.getMinLabelLevel())
                .in(CollectionUtils.isNotEmpty(query.getLabelCodes()), HeroLabelInfo::getLabelCode,
                        query.getLabelCodes())
                .in(CollectionUtils.isNotEmpty(query.getLabelStates()), HeroLabelInfo::getLabelState, query.getLabelStates())
                .ge(Objects.nonNull(query.getCreateTimeStart()), HeroLabelInfo::getCreateTime, query.getCreateTimeStart())
                .le(Objects.nonNull(query.getCreateTimeEnd()), HeroLabelInfo::getCreateTime, query.getCreateTimeEnd())
                .eq(HeroLabelInfo::getState, StateEnum.EFFECTIVE.getCode())
                .orderByAsc(HeroLabelInfo::getShowOrder).orderByDesc(HeroLabelInfo::getId)
        ;

        return this.list(queryWrapper);
    }

    @Override
    public void delByLabelCodes(List<String> labelCodes) {
        log.info("delByLabelCodes param={}", JsonUtils.toJsonWithoutNull(labelCodes));
        if (CollectionUtils.isEmpty(labelCodes)) {
            return;
        }
        List<HeroLabelInfo> labelInfos = this.listByParam(LabelInfoQueryBO.builder().labelCodes(labelCodes).build());
        if (CollectionUtils.isNotEmpty(labelInfos)) {
            List<Long> ids = labelInfos.stream().map(HeroLabelInfo::getId).collect(Collectors.toList());
            HeroLabelInfoService heroLabelInfoService = (HeroLabelInfoService) AopContext.currentProxy();
            heroLabelInfoService.delByIds(ids, null, null, true);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delByIds(List<Long> ids, Integer labelType, Long operaterUid, boolean needDelRelation) {
        log.info("delLabelInfoByIds");
        if (Objects.isNull(operaterUid)) {
            operaterUid = NumConsts.SYSTEM_CODE;
        }
        LambdaUpdateWrapper<HeroLabelInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroLabelInfo::getState, StateEnum.IS_DELETED.getCode())
            .set(HeroLabelInfo::getUpdateBy, operaterUid)
            .in(HeroLabelInfo::getId, ids)
            .eq(Objects.nonNull(labelType), HeroLabelInfo::getLabelType, labelType);
        this.update(updateWrapper);

        if (needDelRelation) {
            userLabelRelationService.delByLabelIds(ids, NumConsts.SYSTEM_CODE);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pullPanguBrandLabels() {
        //调用盘古接口查询手机品牌
        List<BrandBO> allBrand = panGuService.getAllBrandByCate(NumConsts.MOBILE_CATEID);
        if (CollectionUtils.isEmpty(allBrand)) {
            log.info("手机品牌查询为空");
            return;
        }
        //需要顺序
        Map<Integer, String> brandIdNameMap = new LinkedHashMap<>();
        allBrand.forEach(brandBO -> {
            brandIdNameMap.put(brandBO.getId(), brandBO.getName());
        });
        Set<Integer> remoteBrands = brandIdNameMap.keySet();

        //查询标签表里已有的
        List<HeroLabelInfo> dbLabels =
                this.listByParam(LabelInfoQueryBO.builder().labelType(LabelTypeEnum.ADVANTAGE.getCode())
                        .parentLabelCode(LabelCodeEnum.ADVANTAGE_PANGU_MOBILE_BRAND.getCode()).build());
        List<Integer> dbBrandIds = dbLabels.stream().map(label -> this.noFormatBrandLabelCode(label.getLabelCode()))
                .collect(Collectors.toList());

        //----------更新本地数据---------
        //远程有，本地没有的  新增
        List<Integer> insertBrandIds =
                remoteBrands.stream().filter(brandId -> !dbBrandIds.contains(brandId)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(insertBrandIds)) {
            AtomicInteger showOrder = new AtomicInteger(NumConsts.ONE);
            List<HeroLabelInfo> insertLabels = insertBrandIds.stream()
                    .map(brandId -> this.buildBrandLabel(brandId, brandIdNameMap.get(brandId), showOrder.getAndIncrement()))
                    .collect(Collectors.toList());
            log.info("保存品牌标签 param={}", JsonUtils.toJsonWithoutNull(insertLabels));
            this.saveBatch(insertLabels);
        }

        //本地有，远程没有的  标签删除，删除关联关系
        List<Integer> delBrandIds =
                dbBrandIds.stream().filter(brandId -> !remoteBrands.contains(brandId)).collect(Collectors.toList());
        this.delByLabelCodes(delBrandIds.stream().map(this::formatBrandLabelCode).collect(Collectors.toList()));

        //更新labelName或者showOrder
        List<HeroLabelInfo> updateBrandNameRecords = new ArrayList<>();
        //顺序
        AtomicInteger showOrder = new AtomicInteger(NumConsts.ONE);
        brandIdNameMap.forEach((remoteBrandId, remoteBrandName) -> {
            dbLabels.stream().filter(dbLabel -> {
                //labelCode转成brandId 筛选
                Integer brandId = this.noFormatBrandLabelCode(dbLabel.getLabelCode());
                return brandId.equals(remoteBrandId);
            }).findFirst().ifPresent(sameBrandIdRecord -> {
                HeroLabelInfo update = new HeroLabelInfo();
                update.setId(sameBrandIdRecord.getId());
                if (!Objects.equals(remoteBrandName, sameBrandIdRecord.getLabelName())) {
                    //远程的brandName和本地的labelName不一致   更新labelName
                    update.setLabelName(remoteBrandName);
                }
                update.setShowOrder(showOrder.getAndIncrement());
                updateBrandNameRecords.add(update);
            });
        });
        if (CollectionUtils.isNotEmpty(updateBrandNameRecords)) {
            log.info("更新brandName param={}", JsonUtils.toJsonWithoutNull(updateBrandNameRecords));
            this.updateBatchById(updateBrandNameRecords);
        }
    }

    /*@Override
    public List<LevelLabelVO> queryContentCategoryLabels() {
        List<HeroLabelInfo> labelInfos =
            this.listByParam(LabelInfoQueryBO.builder().labelType(LabelTypeEnum.CONTENT_CATEGORY.getCode()).build());
        if (CollectionUtils.isEmpty(labelInfos)) {
            return new ArrayList<>();
        }
        List<LevelLabelVO> levelLabelList = LabelConverter.buildLevelLabel(labelInfos);
        //赋值【品类】的子标签
        this.handlerCateLabel(levelLabelList);
        return levelLabelList;
    }*/

    @Override
    public List<LevelLabelVO> queryContentCategoryLabels(QueryBrandModelLabelDTO queryBrandModelLabelDTO) {
        List<LevelLabelVO> voList = new ArrayList<>();
        String labelCode = queryBrandModelLabelDTO.getLabelCode();
        Integer labelValue = queryBrandModelLabelDTO.getLabelValue();
        if (StringUtils.isBlank(labelCode)) {
            //是第一次调用 返回一级标签
            LabelInfoQueryBO query =
                    LabelInfoQueryBO.builder().labelType(LabelTypeEnum.CONTENT_CATEGORY.getCode()).labelLevel(NumConsts.ONE)
                            .build();
            List<HeroLabelInfo> labelInfos = this.listByParam(query);
            if (CollectionUtils.isEmpty(labelInfos)) {
                return voList;
            }
            return labelInfos.stream().map(LabelConverter::convertLevelLabelVO).collect(Collectors.toList());
        }
        if (LabelCodeEnum.CONTENT_SELLING.getCode().equals(labelCode)) {
            //查询品类
            List<CateBO> displayCates = apolloService.queryDisplayCates();
            return displayCates.stream().map(cate -> this.convertPanguParam2LabelVo(LabelCodeEnum.CONTENT_CATE.getCode(), cate.getId(),
                            cate.getName(), NumConsts.TWO, labelCode, true, false))
                    .collect(Collectors.toList());
        }

        if (LabelCodeEnum.CONTENT_CATE.getCode().equals(labelCode)) {
            if (Objects.isNull(labelValue)) {
                throw new BusinessException("labelValue不可为空");
            }
            //根据品类查品牌
            List<BrandBO> brandList = panGuService.getAllBrandByCate(labelValue);
            if (CollectionUtils.isEmpty(brandList)) {
                log.info("查询品牌为空 cateId={}", labelValue);
                return voList;
            }
            return brandList.stream().map(
                            brand -> this.convertPanguParam2LabelVo(LabelCodeEnum.CONTENT_BRAND.getCode(), brand.getId(),
                                    brand.getName(), NumConsts.THREE, LabelCodeEnum.CONTENT_CATE.getCode(), true,
                                    false))
                    .collect(Collectors.toList());
        }

        if (LabelCodeEnum.CONTENT_BRAND.getCode().equals(labelCode)) {
            if (Objects.isNull(labelValue)) {
                throw new BusinessException("labelValue不可为空");
            }
            //cateId
            Integer parentLabelValue = queryBrandModelLabelDTO.getParentLabelValue();
            if (Objects.isNull(parentLabelValue)) {
                throw new BusinessException("parentLabelValue不可为空");
            }
            //根据品牌查机型
            List<ModelBO> modelList = panGuService.getAllModelByCateAndBrand(parentLabelValue, labelValue);
            if (CollectionUtils.isEmpty(modelList)) {
                log.info("查询机型为空 brandId={}", labelValue);
                return voList;
            }
            return modelList.stream().map(
                            brand -> this.convertPanguParam2LabelVo(LabelCodeEnum.CONTENT_MODEL.getCode(), brand.getModelId(),
                                    //机型这一级把isLast置为true
                                    brand.getModelName(), NumConsts.FOUR, LabelCodeEnum.CONTENT_BRAND.getCode(), true, true))
                    .collect(Collectors.toList());
        }
        if (LabelCodeEnum.CONTENT_MODEL.getCode().equals(labelCode)) {
            if (Objects.isNull(labelValue)) {
                throw new BusinessException("labelValue不可为空");
            }
            //查询【成色】【是否维修过】及其子标签
            LabelInfoQueryBO query = LabelInfoQueryBO.builder().labelType(LabelTypeEnum.CONTENT_CATEGORY.getCode())
                    .minLabelLevel(NumConsts.FIVE).build();
            List<HeroLabelInfo> labelInfos = this.listByParam(query);
            return LabelConverter.buildLevelLabel(labelInfos);
        }

        throw new BusinessException(ExceptionMsgEnum.PARAM_ERROR.getCode(), "labelCode参数错误");
    }

    @Override
    public Long createLabel(CreateLabelBO createLabelBO) {
        HeroLabelInfo saveEntity = this.buildLabelEntity(createLabelBO);
        this.save(saveEntity);
        return saveEntity.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void switchEffective(Long labelId, Integer labelState, Long operaterUid, Date operateTime) {
        HeroLabelInfo labelInfo = this.queryById(labelId);
        Assert.notNull(labelInfo, ExceptionMsgEnum.BUSINESS_ERROR);

        //标签现已关联的用户
        List<Long> relatedUids = new ArrayList<>();
        List<QueryBusinessLabelRelatePO> relateUsers = userLabelRelationService.queryLabelRelatedUsers(labelInfo.getId());
        if (CollectionUtils.isNotEmpty(relateUsers)) {
            relatedUids = relateUsers.stream().map(QueryBusinessLabelRelatePO::getRelatedUid)
                    .collect(Collectors.toList());
        }

        if (LabelStateEnum.INVALID.getCode().equals(labelState)) {
            //下架操作
            if (LabelStateEnum.INVALID.getCode().equals(labelInfo.getLabelState())) {
                log.info("已经是下架状态了");
                return;
            }
            //更新标签状态
            this.updateLabelState(labelId, LabelStateEnum.INVALID.getCode(), operaterUid);
            if (LabelTypeEnum.BUSINESS.getCode().equals(labelInfo.getLabelType())) {
                log.info("使运营标签关联关系失效");
                userLabelRelationService.invalidByLabelIds(Collections.singletonList(labelId), operaterUid);

                //用户解绑运营标签，发送mq
                this.sendBusinessLabelUpdateMsg(labelInfo, relatedUids, BackBusinessLabelUpdateMsg.UNBOUND);
            }
        } else if (LabelStateEnum.EFFECTIVE.getCode().equals(labelState)) {
            //上架操作
            if (LabelStateEnum.EFFECTIVE.getCode().equals(labelInfo.getLabelState())) {
                log.info("已经是上架状态了");
                return;
            }
            this.updateLabelState(labelId, LabelStateEnum.EFFECTIVE.getCode(), operaterUid);
            if (LabelTypeEnum.BUSINESS.getCode().equals(labelInfo.getLabelType())) {

                //要关联的用户取消旧的关联关系  除了本标签之外的
                userLabelRelationService.delByUidAndLabelType(relatedUids, LabelTypeEnum.BUSINESS.getCode(), labelId);

                log.info("使运营标签关联关系生效");
                userLabelRelationService.effectiveByLabelIds(Collections.singletonList(labelId), operaterUid);

                //用户绑定运营标签，发送mq
                this.sendBusinessLabelUpdateMsg(labelInfo, relatedUids, BackBusinessLabelUpdateMsg.BOUND);
            }
        }
    }

    @Override
    public List<HeroLabelInfo> queryAllFraternityAuthLabels(Long uid) {
        return getBaseMapper().queryUserAllLabels(uid, LabelTypeEnum.FRATERNITY_AUTH.getCode(), CreaterRoleEnum.BUSINESS.getCode());
    }

    private void updateLabelState(Long labelId, Integer labelState, Long operaterUid) {
        HeroLabelInfo update = new HeroLabelInfo();
        update.setId(labelId);
        update.setLabelState(labelState);
        update.setUpdateBy(operaterUid);
        this.updateById(update);
    }

    private HeroLabelInfo buildLabelEntity(CreateLabelBO createLabelBO) {
        HeroLabelInfo heroLabelInfo = new HeroLabelInfo();
        Integer labelType = createLabelBO.getLabelType();
        Assert.notNull(labelType, ExceptionMsgEnum.PARAM_ERROR);
        heroLabelInfo.setLabelType(labelType);
        heroLabelInfo.setLabelName(createLabelBO.getLabelName());
        if (LabelTypeEnum.BUSINESS.getCode().equals(labelType)) {
            String labelIcon = createLabelBO.getLabelIcon();
            Assert.notBlank(labelIcon, ExceptionMsgEnum.PARAM_ERROR);
            heroLabelInfo.setLabelIcon(labelIcon);
        }
        heroLabelInfo.setLabelState(createLabelBO.getLabelState());
        heroLabelInfo.setCreaterRole(createLabelBO.getCreaterRole());
        heroLabelInfo.setState(StateEnum.EFFECTIVE.getCode());
        heroLabelInfo.setCreateBy(createLabelBO.getCreaterUid());
        heroLabelInfo.setUpdateBy(createLabelBO.getCreaterUid());
        heroLabelInfo.setCreateTime(createLabelBO.getCreateTime());
        return heroLabelInfo;
    }

    private LevelLabelVO convertPanguParam2LabelVo(String labelCode, Integer paramId, String paramName, Integer labelLevel,
                                                   String parentLabelCode, boolean hasChilds, Boolean isLast) {
        LevelLabelVO vo = new LevelLabelVO();
        vo.setLabelCode(labelCode);
        vo.setLabelName(paramName);
        vo.setLabelValue(paramId);
        vo.setLabelLevel(labelLevel);
        vo.setParentLabelCode(parentLabelCode);
        vo.setHasChilds(hasChilds);
        vo.setIsLast(isLast);
        return vo;
    }

    private HeroLabelInfo buildBrandLabel(Integer brandId, String brandName, int showOrder) {
        HeroLabelInfo labelInfo = new HeroLabelInfo();
        labelInfo.setLabelType(LabelTypeEnum.ADVANTAGE.getCode());
        labelInfo.setLabelCode(this.formatBrandLabelCode(brandId));
        labelInfo.setLabelName(brandName);
        labelInfo.setParentLabelCode(LabelCodeEnum.ADVANTAGE_PANGU_MOBILE_BRAND.getCode());
        labelInfo.setLabelLevel(NumConsts.THREE);
        labelInfo.setShowOrder(showOrder);
        labelInfo.setCreaterRole(CreaterRoleEnum.SYSTEM.getCode());
        labelInfo.setState(StateEnum.EFFECTIVE.getCode());
        labelInfo.setCreateBy(NumConsts.SYSTEM_CODE);
        labelInfo.setUpdateBy(NumConsts.SYSTEM_CODE);
        return labelInfo;
    }

    /**
     * brandId格式化成labelCode
     *
     * @param brandId
     * @return java.lang.String
     * @author hanjunjun
     * @date 2024/6/25
     **/
    private String formatBrandLabelCode(Integer brandId) {
        return LabelTypeEnum.ADVANTAGE.getCode() + Consts.LABEL_CODE_SPLIT + brandId;
    }

    /**
     * labelCode格式化成brandId
     *
     * @param labelCode
     * @return java.lang.Integer
     * @author hanjunjun
     * @date 2024/6/25
     **/
    private Integer noFormatBrandLabelCode(String labelCode) {
        String prefix = LabelTypeEnum.ADVANTAGE.getCode() + Consts.LABEL_CODE_SPLIT;
        return Integer.valueOf(labelCode.substring(prefix.length()));
    }

    /**
     * 用户关联运营标签变更 发送mq
     *
     * @param labelInfo
     * @param boundType 绑定或解绑
     * @return void
     * @author hanjunjun
     * @date 2024/7/11
     **/
    private void sendBusinessLabelUpdateMsg(HeroLabelInfo labelInfo, List<Long> uids, Integer boundType) {
        userLabelRelationService.sendLabelRelationUpdateMsg(labelInfo, uids, boundType);
    }


    /**
     * 根据编码查询标签
     *
     * @param code
     * @return
     */
    @Override
    public List<HeroLabelInfo> queryLabelByCode(String code) {
        LambdaQueryWrapper<HeroLabelInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HeroLabelInfo::getLabelCode, code);

        queryWrapper.orderByAsc(HeroLabelInfo::getShowOrder);
        return list(queryWrapper);
    }

    /**
     * 所有标签类型等于1,2的标签
     */
    @Override
    public List<HeroLabelInfo> queryAllLabelType2() {
        LambdaQueryWrapper<HeroLabelInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(HeroLabelInfo::getLabelType, NumConsts.ONE, NumConsts.TWO);
        queryWrapper.eq(HeroLabelInfo::getState, NumConsts.ONE);
        queryWrapper.orderByAsc(HeroLabelInfo::getShowOrder);
        return list(queryWrapper);
    }

    @Override
    public void increRelatedNum(Long labelId, int relatedNum) {
        log.info("updateRelatedNum labelId={}, relatedNum={}", labelId, relatedNum);
        Assert.notNull(labelId);
        this.getBaseMapper().increRelatedNum(labelId, relatedNum);
    }

    @Override
    public Map<Long, Integer> queryLabelsRelatedNum(List<Long> labelIds) {
        log.info("queryLabelsRelatedNum labelIds={}", JsonUtils.toJsonWithoutNull(labelIds));
        List<LabelRelateNumPO> list = this.getBaseMapper().queryLabelsRelatedNum(labelIds,
                //状态无效的也查
                Arrays.asList(StateEnum.EFFECTIVE.getCode(), StateEnum.INVALID.getCode()));
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        return list.stream().collect(Collectors.toMap(LabelRelateNumPO::getLabelId, LabelRelateNumPO::getRelateNum));
    }
}